1
|
|
|
import PropTypes from 'prop-types'; |
2
|
|
|
import classNames from 'classnames'; |
3
|
|
|
import { Breakpoints, FloatTypes, HorizontalAlignments, VerticalAlignments, SpaceControls, ExtendedBreakpoints } from './enums'; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Property types for general properties. |
7
|
|
|
* |
8
|
|
|
* @returns {Object} |
9
|
|
|
*/ |
10
|
|
|
export const GeneralPropTypes = { |
11
|
|
|
showFor: PropTypes.oneOf([Breakpoints.MEDIUM, Breakpoints.LARGE]), |
12
|
|
|
showOnlyFor: PropTypes.oneOf(objectValues(Breakpoints)), |
13
|
|
|
hideFor: PropTypes.oneOf([Breakpoints.MEDIUM, Breakpoints.LARGE]), |
14
|
|
|
hideOnlyFor: PropTypes.oneOf(objectValues(Breakpoints)), |
15
|
|
|
isHidden: PropTypes.bool, |
16
|
|
|
isInvisible: PropTypes.bool, |
17
|
|
|
showForLandscape: PropTypes.bool, |
18
|
|
|
showForPortrait: PropTypes.bool, |
19
|
|
|
showForSr: PropTypes.bool, |
20
|
|
|
showOnFocus: PropTypes.bool, |
21
|
|
|
isClearfix: PropTypes.bool, |
22
|
|
|
float: PropTypes.oneOf(objectValues(FloatTypes)) |
23
|
|
|
}; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Creates class names from the given arguments. |
27
|
|
|
* |
28
|
|
|
* @param {*} args |
29
|
|
|
* @returns {string} |
30
|
|
|
*/ |
31
|
|
|
export function createClassName(...args) { |
32
|
|
|
return classNames(...args); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Parses the general class names from the given properties. |
37
|
|
|
* |
38
|
|
|
* @param {Object} props |
39
|
|
|
* @returns {Object} |
40
|
|
|
*/ |
41
|
|
|
export function generalClassNames(props) { |
42
|
|
|
return { |
43
|
|
|
'show-for-medium': props.showFor === Breakpoints.MEDIUM, |
44
|
|
|
'show-for-large': props.showFor === Breakpoints.LARGE, |
45
|
|
|
'show-for-small-only': props.showOnlyFor === Breakpoints.SMALL, |
46
|
|
|
'show-for-medium-only': props.showOnlyFor === Breakpoints.MEDIUM, |
47
|
|
|
'show-for-large-only': props.showOnlyFor === Breakpoints.LARGE, |
48
|
|
|
'hide-for-medium': props.hideFor === Breakpoints.MEDIUM, |
49
|
|
|
'hide-for-large': props.hideFor === Breakpoints.LARGE, |
50
|
|
|
'hide-for-small-only': props.hideOnlyFor === Breakpoints.SMALL, |
51
|
|
|
'hide-for-medium-only': props.hideOnlyFor === Breakpoints.MEDIUM, |
52
|
|
|
'hide-for-large-only': props.hideOnlyFor === Breakpoints.LARGE, |
53
|
|
|
'hide': props.isHidden, |
54
|
|
|
'invisible': props.isInvisible, |
55
|
|
|
'show-for-landscape': props.showForLandscape, |
56
|
|
|
'show-for-portrait': props.showForPortrait, |
57
|
|
|
'show-for-sr': props.showForSr, |
58
|
|
|
'show-on-focus': props.showOnFocus, |
59
|
|
|
'clearfix': props.isClearfix, |
60
|
|
|
'float-left': props.float === FloatTypes.LEFT, |
61
|
|
|
'float-center': props.float === FloatTypes.CENTER, |
62
|
|
|
'float-right': props.float === FloatTypes.RIGHT |
63
|
|
|
}; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Returns the keys for the given object. |
68
|
|
|
* This method is used for getting the keys for prop types. |
69
|
|
|
* |
70
|
|
|
* @param {Object} object |
71
|
|
|
* @returns {Array} |
72
|
|
|
*/ |
73
|
|
|
export function objectKeys(object) { |
74
|
|
|
return Object.keys(object); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Returns the values for the given object. |
79
|
|
|
* This method is used for getting the values for enumerables. |
80
|
|
|
* |
81
|
|
|
* @param {Object} object |
82
|
|
|
* @returns {Array} |
83
|
|
|
*/ |
84
|
|
|
export function objectValues(object) { |
85
|
|
|
const values = []; |
86
|
|
|
|
87
|
|
|
for (const property in object) { |
88
|
|
|
if (object.hasOwnProperty(property)) { |
89
|
|
|
values.push(object[property]); |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
return values; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Removes properties from the given object. |
98
|
|
|
* This method is used for removing valid attributes from component props prior to rendering. |
99
|
|
|
* |
100
|
|
|
* @param {Object} object |
101
|
|
|
* @param {Array} remove |
102
|
|
|
* @returns {Object} |
103
|
|
|
*/ |
104
|
|
|
export function removeProps(object, remove) { |
105
|
|
|
const result = {}; |
106
|
|
|
|
107
|
|
|
for (const property in object) { |
108
|
|
|
if (object.hasOwnProperty(property) && remove.indexOf(property) === -1) { |
109
|
|
|
result[property] = object[property]; |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return result; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Returns whether or not the given value is defined. |
118
|
|
|
* |
119
|
|
|
* @param {*} value |
120
|
|
|
* @returns {boolean} |
121
|
|
|
*/ |
122
|
|
|
export function isDefined(value) { |
123
|
|
|
return typeof value !== 'undefined'; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Adds a breakpoint to a class if breakpoint is specified. |
128
|
|
|
* |
129
|
|
|
* @param {String} prop |
130
|
|
|
* @param {String} size |
131
|
|
|
* @returns {string} |
132
|
|
|
*/ |
133
|
|
|
export function addBreakpoint(prop, size) { |
134
|
|
|
return size === 'all' ? prop : `${size}-${prop}`; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Sets direction for grid and gutters (horizontal or vertical). |
139
|
|
|
* |
140
|
|
|
* @param {boolean} isVertical |
141
|
|
|
* @param {String} gutters |
142
|
|
|
* @returns {string} |
143
|
|
|
*/ |
144
|
|
|
export function setDirection(isVertical, gutters = null) { |
145
|
|
|
if (gutters) { |
146
|
|
|
return isVertical === true ? `grid-${gutters}-y` : `grid-${gutters}-x`; |
147
|
|
|
} else { |
148
|
|
|
return isVertical === true ? 'grid-y' : 'grid-x'; |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
// Flexbox Utilities |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Property types for flexbox utilities. |
156
|
|
|
* |
157
|
|
|
* @returns {Object} |
158
|
|
|
*/ |
159
|
|
|
export const FlexboxPropTypes = { |
160
|
|
|
alignX: PropTypes.oneOf(objectValues(HorizontalAlignments)), |
161
|
|
|
alignY: PropTypes.oneOf(objectValues(VerticalAlignments)), |
162
|
|
|
selfAlignX: PropTypes.oneOf(objectValues(HorizontalAlignments)), |
163
|
|
|
selfAlignY: PropTypes.oneOf(objectValues(VerticalAlignments)), |
164
|
|
|
centerAlign: PropTypes.bool, |
165
|
|
|
flexContainer: PropTypes.bool, |
166
|
|
|
flexDirRow: PropTypes.oneOf(objectValues(ExtendedBreakpoints)), |
167
|
|
|
flexDirRowRev: PropTypes.oneOf(objectValues(ExtendedBreakpoints)), |
168
|
|
|
flexDirCol: PropTypes.oneOf(objectValues(ExtendedBreakpoints)), |
169
|
|
|
flexDirColRev: PropTypes.oneOf(objectValues(ExtendedBreakpoints)), |
170
|
|
|
flexChild: PropTypes.oneOf(objectValues(SpaceControls)), |
171
|
|
|
flexOrder: PropTypes.number, |
172
|
|
|
flexOrderSmall: PropTypes.number, |
173
|
|
|
flexOrderMedium: PropTypes.number, |
174
|
|
|
flexOrderLarge: PropTypes.number, |
175
|
|
|
}; |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Parses the flexbox class names from the given properties. |
179
|
|
|
* |
180
|
|
|
* @param {Object} props |
181
|
|
|
* @returns {Object} |
182
|
|
|
*/ |
183
|
|
|
export function flexboxClassNames(props) { |
184
|
|
|
const flexClassNames = { |
185
|
|
|
'flex-container': props.flexContainer, |
186
|
|
|
'align-center-middle': props.centerAlign, |
187
|
|
|
}; |
188
|
|
|
|
189
|
|
|
if (isDefined(props.alignX)) flexClassNames[`align-${props.alignX}`] = true; |
|
|
|
|
190
|
|
|
if (isDefined(props.alignY)) flexClassNames[`align-${props.alignY}`] = true; |
|
|
|
|
191
|
|
|
if (isDefined(props.flexDirRow)) flexClassNames[addBreakpoint('flex-dir-row', props.flexDirRow)] = true; |
|
|
|
|
192
|
|
|
if (isDefined(props.flexDirRowRev)) flexClassNames[addBreakpoint('flex-dir-row-reverse', props.flexDirRowRev)] = true; |
|
|
|
|
193
|
|
|
if (isDefined(props.flexDirCol)) flexClassNames[addBreakpoint('flex-dir-column', props.flexDirCol)] = true; |
|
|
|
|
194
|
|
|
if (isDefined(props.flexDirColRev)) flexClassNames[addBreakpoint('flex-dir-column-reverse', props.flexDirColRev)] = true; |
|
|
|
|
195
|
|
|
if (isDefined(props.flexChild)) flexClassNames[`flex-child-${props.flexChild}`] = true; |
|
|
|
|
196
|
|
|
if (isDefined(props.flexOrder)) flexClassNames[`order-${props.flexOrder}`] = true; |
|
|
|
|
197
|
|
|
if (isDefined(props.flexOrderSmall)) flexClassNames[`small-order-${props.flexOrder}`] = true; |
|
|
|
|
198
|
|
|
if (isDefined(props.flexOrderMedium)) flexClassNames[`medium-order-${props.flexOrder}`] = true; |
|
|
|
|
199
|
|
|
if (isDefined(props.flexOrderLarge)) flexClassNames[`large-order-${props.flexOrder}`] = true; |
|
|
|
|
200
|
|
|
|
201
|
|
|
return flexClassNames; |
202
|
|
|
} |
203
|
|
|
|
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.